﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using IPC.Communication.Core.Net;

namespace IPC.Communication.Profinet.Sick
{
    public class SickIcrTcpServer : NetworkServerBase
    {
        public delegate void ReceivedBarCodeDelegate(string ipAddress, string barCode);

        private int clientCount = 0;

        private List<AppSession> initiativeClients;

        private object lockClients;

        public int OnlineCount { get { return clientCount; } set { clientCount = value; } }

        public event ReceivedBarCodeDelegate OnReceivedBarCode;

        public SickIcrTcpServer()
        {
            initiativeClients = new List<AppSession>();
            lockClients = new object();
        }

        protected override void ThreadPoolLogin(Socket socket, IPEndPoint endPoint)
        {
            AppSession appSession = new AppSession();
            appSession.IpEndPoint = endPoint;
            appSession.IpAddress = endPoint.Address.ToString();
            appSession.WorkSocket = socket;
            try
            {
                socket.BeginReceive(new byte[0], 0, 0, SocketFlags.None, SocketAsyncCallBack, appSession);
                AddClient(appSession);
            }
            catch
            {
                socket.Close();
                if (base.LogNet != null)
                {
                    base.LogNet.WriteDebug(ToString(), string.Format(StringResources.Language.ClientOfflineInfo, endPoint));
                }
            }
        }

        private void SocketAsyncCallBack(IAsyncResult ar)
        {
            AppSession appSession = ar.AsyncState as AppSession;
            if (appSession != null)
            {
                try
                {
                    appSession.WorkSocket.EndReceive(ar);
                    byte[] array = new byte[1024];
                    int num = appSession.WorkSocket.Receive(array);
                    if (num > 0)
                    {
                        byte[] array2 = new byte[num];
                        Array.Copy(array, 0, array2, 0, num);
                        appSession.WorkSocket.BeginReceive(new byte[0], 0, 0, SocketFlags.None, SocketAsyncCallBack, appSession);

                            if (this.OnReceivedBarCode != null)
                            {
                                this.OnReceivedBarCode.Invoke(appSession.IpAddress, TranslateCode(Encoding.ASCII.GetString(array2)));
                            }
                        
                    }
                    else
                    {
                        if (appSession.WorkSocket != null)
                        {
                            appSession.WorkSocket.Close();
                        }
                        if (base.LogNet != null)
                        {
                            base.LogNet.WriteDebug(ToString(), string.Format(StringResources.Language.ClientOfflineInfo, appSession.IpEndPoint));
                        }
                        RemoveClient(appSession);
                    }
                }
                catch
                {
                    if (appSession.WorkSocket != null)
                    {
                        appSession.WorkSocket.Close();
                    }
                    if (base.LogNet != null)
                    {
                        base.LogNet.WriteDebug(ToString(), string.Format(StringResources.Language.ClientOfflineInfo, appSession.IpEndPoint));
                    }

                    RemoveClient(appSession);
                }
            }
        }

        private string TranslateCode(string code)
        {
            StringBuilder stringBuilder = new StringBuilder("");
            for (int i = 0; i < code.Length; i++)
            {
                if (char.IsLetterOrDigit(code, i))
                {
                    stringBuilder.Append(code[i]);
                }
            }
            return stringBuilder.ToString();
        }

        public void AddConnectBarcodeScan(string ipAddress, int port)
        {
            IPEndPoint iPEndPoint = new IPEndPoint(IPAddress.Parse(ipAddress), port);
            AppSession appSession = new AppSession();
            appSession.IpEndPoint = iPEndPoint;
            appSession.IpAddress = iPEndPoint.Address.ToString();
            ThreadPool.QueueUserWorkItem(ConnectBarcodeScan, appSession);
        }

        private void ConnectBarcodeScan(object obj)
        {
            AppSession appSession = obj as AppSession;
            if (appSession != null)
            {
                OperateResult<Socket> operateResult = CreateSocketAndConnect(appSession.IpEndPoint, 5000);
                if (!operateResult.IsSuccess)
                {
                    Thread.Sleep(1000);
                    ThreadPool.QueueUserWorkItem(ConnectBarcodeScan, appSession);
                }
                else
                {
                    appSession.WorkSocket = operateResult.Content;
                    try
                    {
                        appSession.WorkSocket.BeginReceive(new byte[0], 0, 0, SocketFlags.None, InitiativeSocketAsyncCallBack, appSession);
                        AddClient(appSession);
                    }
                    catch
                    {
                        appSession.WorkSocket.Close();
                        ThreadPool.QueueUserWorkItem(ConnectBarcodeScan, appSession);
                    }
                }
            }
        }

        private void InitiativeSocketAsyncCallBack(IAsyncResult ar)
        {
            AppSession appSession = ar.AsyncState as AppSession;
            if (appSession != null)
            {
                try
                {
                    appSession.WorkSocket.EndReceive(ar);
                    byte[] array = new byte[1024];
                    int num = appSession.WorkSocket.Receive(array);
                    if (num > 0)
                    {
                        byte[] array2 = new byte[num];
                        Array.Copy(array, 0, array2, 0, num);
                        appSession.WorkSocket.BeginReceive(new byte[0], 0, 0, SocketFlags.None, InitiativeSocketAsyncCallBack, appSession);
                        
                            if (this.OnReceivedBarCode != null)
                            {
                                this.OnReceivedBarCode.Invoke(appSession.IpAddress, TranslateCode(Encoding.ASCII.GetString(array2)));
                            }
                        
                    }
                    else
                    {
                        if (appSession.WorkSocket != null)
                        {
                            appSession.WorkSocket.Close();
                        }
                        if (base.LogNet != null)
                        {
                            base.LogNet.WriteDebug(ToString(), string.Format(StringResources.Language.ClientOfflineInfo, appSession.IpEndPoint));
                        }
                        RemoveClient(appSession);
                    }
                }
                catch
                {
                    if (appSession.WorkSocket != null)
                    {
                        appSession.WorkSocket.Close();
                    }
                    if (base.LogNet != null)
                    {
                        base.LogNet.WriteDebug(ToString(), string.Format(StringResources.Language.ClientOfflineInfo, appSession.IpEndPoint));
                    }
                    RemoveClient(appSession);
                    if (base.IsStarted)
                    {
                        ConnectBarcodeScan(appSession);
                    }
                }
            }
        }

        private void AddClient(AppSession session)
        {
            lock (lockClients)
            {
                clientCount++;
                initiativeClients.Add(session);
            }
        }

        private void RemoveClient(AppSession session)
        {
            lock (lockClients)
            {
                clientCount--;
                initiativeClients.Remove(session);
            }
        }

        protected override void CloseAction()
        {
            lock (lockClients)
            {
                for (int i = 0; i < initiativeClients.Count; i++)
                {
                    if (initiativeClients[i].WorkSocket != null)
                    {
                        initiativeClients[i].WorkSocket.Close();
                    }
                }
                initiativeClients.Clear();
            }
        }

        public override string ToString()
        {
            return String.Format("SickIcrTcpServer[{0}]", base.Port);
        }
    }
}